package com.tron.sync.syncwfinfoindex;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.tron.sync.entities.ElkUserInfo;
import com.tron.sync.entities.Wfinfoindex;
import com.tron.sync.entities.WfinfoindexDTO;
import com.tron.sync.service.ElkUserInfoService;
import com.tron.sync.service.SyndaOrgService;
import com.tron.sync.service.WfinfoIndexService;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.SearchScrollHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 1.
 */
@Slf4j
@Service
public class SyncWfInfoIndex {
    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Autowired
    private PlatformClient platformClient;

    @Autowired
    private WfinfoIndexService wfinfoIndexService;

    @Autowired
    ElkUserInfoService elkUserInfoService;

    @Autowired
    SyndaOrgService syndaOrgService;


    public List<Wfinfoindex> queryListElkData(String orgId, String token) {
        final ArrayList<Wfinfoindex> result = new ArrayList<>();
        try {
            // 查询该机构下的用户
            final String query = platformClient.queryOrgUserRelation(JSON.parseObject("{\"parameters\":[{\"key\":\"orgId\",\"value\":\"" + orgId + "\"},{\"key\":\"hassub\",\"value\":\"0\"},{\"key\":\"roleId\",\"value\":\"\"}],\"requestPage\":{\"pageNo\":1,\"limit\":2000,\"totalCount\":3},\"sorts\":[]}"), token);
            final JSONArray jsonArray = JSONObject.parseObject(query).getJSONObject("data").getJSONArray("dataResult");
            List<String> ids = jsonArray.stream().map(j -> {
                JSONObject jsonObject = (JSONObject) j;
                return jsonObject.getString("id");
            }).collect(Collectors.toList());
            final String collect = ids.stream().collect(Collectors.joining(" OR "));
            //如果创建机构是orgId，但是创建部门却不是我们查到的下级部门，那么，该数据就是错误的。
            QueryBuilder queryBuilder = QueryBuilders.boolQuery()
                    .must(QueryBuilders.queryStringQuery(collect).field("createBy"))
                    .mustNot(QueryBuilders.matchQuery("createDepId", ""))
                    .must(QueryBuilders.matchQuery("createOrgId", orgId));
            NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryBuilder);
            System.out.println(nativeSearchQuery.getQuery().toString());
            nativeSearchQuery.setMaxResults(100);
            List<Wfinfoindex> wfinfoindices = toDoSearch(nativeSearchQuery, 100, token);
            result.addAll(wfinfoindices);
        } catch (Exception e) {
            System.out.println("查询用户异常：" + e.getMessage());
        }
        if (!result.isEmpty()) {
            List<WfinfoindexDTO> wfinfoindexDTOS = new ArrayList<>();
            result.forEach(e -> {
                WfinfoindexDTO wfinfoindexDTO = new WfinfoindexDTO();
                BeanUtils.copyProperties(e, wfinfoindexDTO);
                wfinfoindexDTOS.add(wfinfoindexDTO);
            });
            wfinfoIndexService.saveWfinfoIndex(wfinfoindexDTOS);
        }
        return result;
    }

    public HashMap<String, Object> updateElkErrorData(String token) {
        final HashMap<String, Object> hashMap = new HashMap<>();
        final List<String> orgIds = syndaOrgService.findOrgByType(2);
        orgIds.forEach(id -> {
            List<Wfinfoindex> wfinfoindices = queryListElkData(id, token);
            wfinfoindices.forEach(w -> {
                w.setCreateDepId("");
                w.setCreateDep("");
            });
            System.out.println(id + " 需要修改数据条数：" + wfinfoindices.size());
            hashMap.put(id, wfinfoindices.size());
            elasticsearchRestTemplate.save(wfinfoindices);
        });
        return hashMap;
    }

    public HashMap<String, Object> updateElkErrorDataByOrgId(String orgId,String token) {
        final HashMap<String, Object> hashMap = new HashMap<>();
            List<Wfinfoindex> wfinfoindices = queryListElkData(orgId, token);
            wfinfoindices.forEach(w -> {
                w.setCreateDepId("");
                w.setCreateDep("");
            System.out.println(orgId + " 需要修改数据条数：" + wfinfoindices.size());
            hashMap.put(orgId, wfinfoindices.size());
            elasticsearchRestTemplate.save(wfinfoindices);
        });
        return hashMap;
    }

    public HashMap<String, Object> updateElkErrorDataById(String id) {
        final NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        final NativeSearchQuery query = nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("_id", id)).build();
        final SearchHits<Wfinfoindex> search = elasticsearchRestTemplate.search(query, Wfinfoindex.class);
        final List<SearchHit<Wfinfoindex>> searchHits = search.getSearchHits();
        final List<Wfinfoindex> collect = searchHits.stream().map(SearchHit::getContent).collect(Collectors.toList());
        final HashMap<String, Object> hashMap = new HashMap<>();
        collect.forEach(w -> {
            w.setCreateDepId("");
            w.setCreateDep("");
            elasticsearchRestTemplate.save(w);
            hashMap.put("data", w);
        });
        return hashMap;
    }




    public Wfinfoindex getWfinfoindex(String orgId, String token) {
        //根据机构Id获取下级： 此处我们先传入十六个州市的Id，拿到下面的所有内设机构的Id；
        String orgByParentId = platformClient.findOrgByParentId(orgId, token);
        List<String> orgIds = getIds(orgByParentId, "org");
        log.info("获取到的所有内设机构有======================={}", orgIds);
        orgIds.forEach(o -> {
            //在拿着内设机构的Id查询到所有下级部门；
//            String deptIds = platformClient.findOrgByParentId(o, token);
//            log.info("当前查询内设机构为==={}===================查询到的下级部门有{}", o, deptIds);
//            List<String> deptResponse = getIds(deptIds, "org");
//            String collect = deptResponse.stream().collect(Collectors.joining(" OR "));
            final String query = platformClient.queryOrgUserRelation(JSON.parseObject("{\"parameters\":[{\"key\":\"orgId\",\"value\":\"785915834471022592\"},{\"key\":\"hassub\",\"value\":\"0\"},{\"key\":\"roleId\",\"value\":\"\"}],\"requestPage\":{\"pageNo\":1,\"limit\":2000,\"totalCount\":3},\"sorts\":[]}"), "edd4e2b0804611eb133a081c17cdb4ce");
            final JSONArray jsonArray = JSONObject.parseObject(query).getJSONObject("data").getJSONArray("dataResult");
            final List<String> ids = jsonArray.stream().map(j -> {
                JSONObject jsonObject = (JSONObject) j;
                return jsonObject.getString("id");
            }).collect(Collectors.toList());
            final String collect = ids.stream().collect(Collectors.joining(" OR "));
            //如果创建机构是orgId，但是创建部门却不是我们查到的下级部门，那么，该数据就是错误的。
            QueryBuilder queryBuilder = QueryBuilders.boolQuery()
                    .must(QueryBuilders.queryStringQuery(collect).field("createBy"))
                    .mustNot(QueryBuilders.matchQuery("createDepId", ""))
                    .must(QueryBuilders.matchQuery("createOrgId", o));
//                    .must(QueryBuilders.queryStringQuery(us).field("createBy"));
            NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryBuilder);
            System.out.println(nativeSearchQuery.toString());
            nativeSearchQuery.setMaxResults(100);
            toDo(nativeSearchQuery, 100, token);
//            List<WfinfoindexDTO> wfinfoindexDTOS = new ArrayList<>();
//            for (int i = 0; i <searchHits.size() ; i++) {
//                Wfinfoindex content = searchHits.get(i).getContent();
//                WfinfoindexDTO wfinfoindexDTO = new WfinfoindexDTO();
//                BeanUtils.copyProperties(content,wfinfoindexDTO);
//                wfinfoindexDTOS.add(wfinfoindexDTO);
//            }
//            wfinfoIndexService.saveWfinfoIndex(wfinfoindexDTOS);
        });
        return null;

    }

    private List<Wfinfoindex> toDoSearch(Query nativeSearchQuery, long maxResult, String token) {
        ArrayList<Wfinfoindex> wfinfoindices = new ArrayList<>();
        // 创建滚动查询
        SearchScrollHits<Wfinfoindex> wfinfoindex = elasticsearchRestTemplate.searchScrollStart(500000, nativeSearchQuery, Wfinfoindex.class, IndexCoordinates.of("wfinfoindex"));
        String scrollId = wfinfoindex.getScrollId();
        final long totalHits = wfinfoindex.getTotalHits();
        if (totalHits < maxResult) {
            // 返回结果总数小于最大结果数，表示不需要滚动查询。直接处理结果集
            wfinfoindex.getSearchHits().forEach(e -> {
                wfinfoindices.add(e.getContent());
            });
            elasticsearchRestTemplate.searchScrollClear(Arrays.asList(scrollId));
        } else {
            // 先处理首次查询到的结果
            final ArrayList<String> scrollIds = new ArrayList<>();
            scrollIds.add(scrollId);
            final List<SearchHit<Wfinfoindex>> firstResult = wfinfoindex.getSearchHits();
            firstResult.forEach(e -> {
                wfinfoindices.add(e.getContent());
            });
            // 滚动查询
            while (true) {
                final SearchScrollHits<Wfinfoindex> hits = elasticsearchRestTemplate.searchScrollContinue(scrollId, 500000, Wfinfoindex.class, IndexCoordinates.of("wfinfoindex"));
                final List<SearchHit<Wfinfoindex>> searchHitList = hits.getSearchHits();
                // 结果总数为0时退出循环
                if (searchHitList.size() == 0) {
                    break;
                }
                scrollId = hits.getScrollId();
                scrollIds.add(scrollId);
                // 处理结果集
                searchHitList.forEach(e -> {
                    wfinfoindices.add(e.getContent());
                });
            }
            elasticsearchRestTemplate.searchScrollClear(scrollIds);
        }
        return wfinfoindices;
    }


    /**
     * 滚动查询，并把全文检索中的用户数据保存保存到数据库中
     */
    private void toDo(Query nativeSearchQuery, long maxResult, String token) {
        // 创建滚动查询
        SearchScrollHits<Wfinfoindex> wfinfoindex = elasticsearchRestTemplate.searchScrollStart(500000, nativeSearchQuery, Wfinfoindex.class, IndexCoordinates.of("wfinfoindex"));
        String scrollId = wfinfoindex.getScrollId();
        final long totalHits = wfinfoindex.getTotalHits();
        System.out.println("=======待处理数据的总条数=========" + totalHits);
        if (totalHits < maxResult) {
            // 返回结果总数小于最大结果数，表示不需要滚动查询。直接处理结果集
            System.out.println("===========不需要滚动查询===========" + totalHits);
            handlerResult(wfinfoindex.getSearchHits(), token, false);
            elasticsearchRestTemplate.searchScrollClear(Arrays.asList(scrollId));
        } else {
            // 先处理首次查询到的结果
            final ArrayList<String> scrollIds = new ArrayList<>();
            scrollIds.add(scrollId);
            final List<SearchHit<Wfinfoindex>> firstResult = wfinfoindex.getSearchHits();
            System.out.println("=========firstResult=========" + firstResult.size());
            handlerResult(firstResult, token, false);

            // 滚动查询
            while (true) {
                final SearchScrollHits<Wfinfoindex> hits = elasticsearchRestTemplate.searchScrollContinue(scrollId, 500000, Wfinfoindex.class, IndexCoordinates.of("wfinfoindex"));
                final List<SearchHit<Wfinfoindex>> searchHitList = hits.getSearchHits();
                // 结果总数为0时退出循环
                if (searchHitList.size() == 0) {
                    break;
                }
                scrollId = hits.getScrollId();
                scrollIds.add(scrollId);
                // 处理结果集
                System.out.println("========处理结果集=======：" + searchHitList.size());
                handlerResult(searchHitList, token, false);
            }
            elasticsearchRestTemplate.searchScrollClear(scrollIds);
        }
    }

    // 读取handlerList 和 pendingList中的用户数据
    public List<Wfinfoindex> handlerResult(List<SearchHit<Wfinfoindex>> list, String token, Boolean sync) {
        final ArrayList<Wfinfoindex> wfinfoindices = new ArrayList<>();
        list.forEach(s -> {
            // 每一条数据的处理方式
            final Wfinfoindex wfinfoindex = s.getContent();

            List<String> penddingList = wfinfoindex.getPenddingList();
            System.out.println("原p=======" + penddingList);
            List<String> newPendingList = updateList(token, penddingList);
            System.out.println("新p=======" + newPendingList);

            List<String> handleList = wfinfoindex.getHandleList();
            System.out.println("原h=======" + handleList);
            List<String> newHandlerList = updateList(token, handleList);
            System.out.println("新h=======" + newHandlerList);

            // 如果需要把数据中刷新到elk
            if (sync) {
                wfinfoindex.setHandleList(newHandlerList);
                wfinfoindex.setPenddingList(newPendingList);
                updateElk(wfinfoindex);
                wfinfoindices.add(wfinfoindex);
            }
        });
        return wfinfoindices;
    }

    // 保存用户中心和全文检索中的用户数据，返回用用户中心用户数据跟新的pendingList或者handlerList
    private List<String> updateList(String token, List<String> stringList) {
        ArrayList<String> strings = new ArrayList<>();
        stringList.forEach(p -> {
            SearchExecuteEntity pEntity = SearchExecuteEntity.parseToObject(p);
            SearchExecuteEntity newEntity = new SearchExecuteEntity();
            // 把用户信息存储到数据库
            final String assignUserId = pEntity.getAssignUserId();
            final String assignUser = pEntity.getAssignUser();
            final String orgId = pEntity.getOrgId();
            final String orgName = pEntity.getOrg();
            final String depId = pEntity.getDepId();
            final String depName = pEntity.getDep();
            final String sendUserId = pEntity.getSendUserId();
            final String sendUser = pEntity.getSendUser();
            final String sendOrgId = pEntity.getSendOrgId();
            final String sendOrgName = pEntity.getSendOrg();
            final String sendDepId = pEntity.getSendDepId();
            final String sendDepName = pEntity.getSendDep();

            if (StringUtils.hasText(assignUserId)) {
                // 获取用户中心用户数据
                ElkUserInfo userCenterInfo = elkUserInfoService.getUserCenterInfo(token, assignUserId);
                if (null != userCenterInfo) {
                    newEntity.setAssignUserId(userCenterInfo.getUserId());
                    newEntity.setAssignUser(userCenterInfo.getS_userName());
                    newEntity.setOrgId(userCenterInfo.getS_orgId());
                    newEntity.setOrg(userCenterInfo.getS_orgName());
                    newEntity.setDepId(userCenterInfo.getS_deptId());
                    newEntity.setDep(userCenterInfo.getS_deptName());
                    userCenterInfo.setUserId(assignUserId);
                    userCenterInfo.setUserName(assignUser);
                    userCenterInfo.setOrgId(orgId);
                    userCenterInfo.setOrgName(orgName);
                    userCenterInfo.setDeptId(depId);
                    userCenterInfo.setDeptName(depName);
                    elkUserInfoService.saveOrUpdate(userCenterInfo);
                }
            }
            if (StringUtils.hasText(sendUserId)) {
                // 获取用户中心用户数据
                ElkUserInfo userCenterInfo = elkUserInfoService.getUserCenterInfo(token, sendUserId);
                if (null != userCenterInfo) {
                    newEntity.setSendUserId(userCenterInfo.getUserId());
                    newEntity.setSendUser(userCenterInfo.getS_userName());
                    newEntity.setSendOrgId(userCenterInfo.getS_orgId());
                    newEntity.setSendOrg(userCenterInfo.getS_orgName());
                    newEntity.setSendDepId(userCenterInfo.getS_deptId());
                    newEntity.setSendDep(userCenterInfo.getS_deptName());
                    userCenterInfo.setUserId(sendUserId);
                    userCenterInfo.setUserName(sendUser);
                    userCenterInfo.setOrgId(sendOrgId);
                    userCenterInfo.setOrgName(sendOrgName);
                    userCenterInfo.setDeptId(sendDepId);
                    userCenterInfo.setDeptName(sendDepName);
                    elkUserInfoService.saveOrUpdate(userCenterInfo);
                }
            }


            strings.add(newEntity.toString());
        });
        return strings;
    }


    private List<String> getIds(String response, String type) {
        List<String> ids = new ArrayList<>();
        if (response == null) {
            return ids;
        }
        JSONObject jsonObject = JSONObject.parseObject(response);
        if (!jsonObject.containsKey("state") || jsonObject.getInteger("state") != 200) {
            return ids;
        }
        JSONArray data = null;
        if ("org".equalsIgnoreCase(type)) {
            data = jsonObject.getJSONArray("data");
        }
        if ("user".equalsIgnoreCase(type)) {
            data = jsonObject.getJSONObject("data").getJSONArray("dataResult");
        }

        for (int i = 0; i < data.size(); i++) {
            JSONObject o = (JSONObject) data.get(i);
            ids.add(o.getString("id"));
        }
        return ids;
    }

    private Wfinfoindex updateElk(Wfinfoindex wfinfoindex) {
        final Wfinfoindex save = elasticsearchRestTemplate.save(wfinfoindex);
        return save;
    }

    private JSONObject getQueryParams(String orgId) {
        String params = "{\"parameters\":[{\"key\":\"hassub\",\"value\":\"0\"},{\"key\":\"orgId\",\"value\":\"" + orgId + "\"},{\"key\":\"roleId\",\"value\":\"\"}],\"requestPage\":{\"pageNo\":1,\"limit\":100,\"totalCount\":23},\"sorts\":[]}";
        return JSONObject.parseObject(params);
    }


    public List<SearchHit<Wfinfoindex>> getElkById(String id) {
        final NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        final NativeSearchQuery query = nativeSearchQueryBuilder.withQuery(QueryBuilders.matchQuery("_id", id)).build();
        final SearchHits<Wfinfoindex> search = elasticsearchRestTemplate.search(query, Wfinfoindex.class);
        final List<SearchHit<Wfinfoindex>> searchHits = search.getSearchHits();
        return searchHits;
    }

    public Map updateElkDataById(String id, String token) {
        final List<SearchHit<Wfinfoindex>> elkById = getElkById(id);
        final List<Wfinfoindex> oldData = elkById.stream().map(SearchHit::getContent).collect(Collectors.toList());
        final List<Wfinfoindex> newData = handlerResult(elkById, token, true);
        final HashMap<String, Object> hashMap = new HashMap<>();
        hashMap.put("oldData", oldData);
        hashMap.put("newData", newData);
        return hashMap;
    }
}
